<!DOCTYPE html>
<html lang="en">

<!-- Head tag -->
<head><meta name="generator" content="Hexo 3.9.0">

    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">

    <!--Description-->
    

    <!--Author-->
    
        <meta name="author" content="ck">
    

    <!--Open Graph Title-->
    
        <meta property="og:title" content="CK&#39;s blogs">
    

    <!--Open Graph Description-->
    

    <!--Open Graph Site Name-->
    <meta property="og:site_name" content="CK&#39;s blogs">

    <!--Type page-->
    
        <meta property="og:type" content="website">
    

    <!--Page Cover-->
    

    <meta name="twitter:card" content="summary">
    

    <!-- Title -->
    
    <title>page - CK&#39;s blogs</title>

    <!-- Bootstrap Core CSS -->
    <link rel="stylesheet" href="//maxcdn.bootstrapcdn.com/bootstrap/4.0.0-alpha.2/css/bootstrap.min.css" integrity="sha384-y3tfxAZXuh4HwSYylfB+J125MxIs6mR5FOHamPBG064zB+AFeWH94NdvaCBm8qnd" crossorigin="anonymous">

    <!-- Custom Fonts -->
    <link href="//maxcdn.bootstrapcdn.com/font-awesome/4.6.3/css/font-awesome.min.css" rel="stylesheet" type="text/css">

    <!-- HTML5 Shim and Respond.js IE8 support of HTML5 elements and media queries -->
    <!-- WARNING: Respond.js doesn't work if you view the page via file:// -->
    <!--[if lt IE 9]>
        <script src="//oss.maxcdn.com/libs/html5shiv/3.7.0/html5shiv.js"></script>
        <script src="//oss.maxcdn.com/libs/respond.js/1.4.2/respond.min.js"></script>
    <![endif]-->

    <!-- Gallery -->
    <link href="//cdnjs.cloudflare.com/ajax/libs/featherlight/1.3.5/featherlight.min.css" type="text/css" rel="stylesheet">

    <!-- Custom CSS -->
    <link rel="stylesheet" href="/blog/css/style.css">

    <!-- Google Analytics -->
    


</head>


<body>

<div class="bg-gradient"></div>
<div class="bg-pattern"></div>

<!-- Menu -->
<!--Menu Links and Overlay-->
<div class="menu-bg">
    <div class="menu-container">
        <ul>
            
            <li class="menu-item">
                <a href="/blog/">
                    Home
                </a>
            </li>
            
            <li class="menu-item">
                <a href="/blog/archives">
                    Archives
                </a>
            </li>
            
            <li class="menu-item">
                <a href="/blog/2019/09/04/本人简历/">
                    About
                </a>
            </li>
            
            <li class="menu-item">
                <a href="/blog/tags">
                    Tags
                </a>
            </li>
            
            <li class="menu-item">
                <a href="/blog/categories">
                    Categories
                </a>
            </li>
            
            <li class="menu-item">
                <a href="/blog/contact.html">
                    Contact
                </a>
            </li>
            
        </ul>
    </div>
</div>

<!--Hamburger Icon-->
<nav>
    <a href="#menu"></a>
</nav>

<div class="container">

    <!-- Main Content -->
    <div class="row">
    <div class="col-sm-12">

        <!--Title and Logo-->
        <header>
    <div class="logo">
        <a href="/blog/"><i class="logo-icon fa fa-cube" aria-hidden="true"></i></a>
        
            <h1 id="main-title" class="title">CK's blogs</h1>
        
    </div>
</header>

        <section class="main">
            
                
<div class="post">

    <div class="post-header index">
        <h1 class="title">
            <a href="/blog/2019/06/05/Django-Nginx-uWSGI安装配置/">
                Django+Nginx+uWSGI安装配置
            </a>
        </h1>
        <div class="post-info">
            
                <span class="date">2019-06-05</span>
            
            
            
        </div>
    </div>

    
        <div class="content">
            <p>链接：🔗</p>
<p><a href="https://www.runoob.com/django/django-nginx-uwsgi.html" target="_blank" rel="noopener">https://www.runoob.com/django/django-nginx-uwsgi.html</a></p>
<blockquote>
<p>yum update</p>
<p>yum install gcc</p>
<p>pip install uwsgi</p>
</blockquote>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br></pre></td><td class="code"><pre><span class="line">查看uwsgi动态链接库是否有问题：</span><br><span class="line">which  uwsgi</span><br><span class="line">ldd /root/anaconda3/bin/uwsgi</span><br><span class="line">发现:libicui18n.so.58 =&gt; not found</span><br><span class="line">     libicuuc.so.58 =&gt; not found</span><br><span class="line">     libicudata.so.58 =&gt; not found</span><br><span class="line">通过 LDD 发现 uwsgi 找不到三个包（具体就是 not found 的三个）</span><br><span class="line">于是就把anaconda3/lib 下相应的包软链到/lib64下去（64bit 机器，如果时32bit 机器则软链到/lib下）</span><br><span class="line"></span><br><span class="line">[root@localhost ~]# ln -s /root/anaconda3/lib/libicui18n.so.58 /lib64/libicui18n.so.58</span><br><span class="line">[root@localhost ~]# ln -s /root/anaconda3/lib/libicuuc.so.58 /lib64/libicuuc.so.58</span><br><span class="line">[root@localhost ~]# ln -s /root/anaconda3/lib/libicudata.so.58 /lib64/libicudata.so.58</span><br><span class="line">运行uwsgi:发现还有问题</span><br><span class="line">于是：</span><br><span class="line">    把libstdc++.so.6.0.24拷贝到/lib64目录下。</span><br><span class="line">      cp /root/anaconda3/lib/libstdc++.so.6.0.25 /lib64/</span><br><span class="line">    删除原来的libstdc++.so.6符号连接。</span><br><span class="line">      rm -fr /lib64/libstdc++.so.6</span><br><span class="line">    新建新符号连接。</span><br><span class="line">      ln -s /lib64/libstdc++.so.6.0.25 /lib64/libstdc++.so.6</span><br><span class="line">    再次执行uwsgi查看结果符合就哦了。</span><br></pre></td></tr></table></figure>

<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">测试：创建index.py</span><br><span class="line">def application(env, start_response):</span><br><span class="line">    start_response(&apos;200 OK&apos;, [(&apos;Content-Type&apos;,&apos;text/html&apos;)])</span><br><span class="line">    return [b&quot;Hello World&quot;]</span><br><span class="line"></span><br><span class="line">uwsgi --http :9090 --wsgi-file index.py</span><br><span class="line">浏览器访问9090端口</span><br></pre></td></tr></table></figure>

<h6 id="添加并发"><a href="#添加并发" class="headerlink" title="添加并发"></a>添加并发</h6><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">uwsgi --http :9090 --wsgi-file index.py --processes 4 --threads 2</span><br></pre></td></tr></table></figure>

<h6 id="部署-Django"><a href="#部署-Django" class="headerlink" title="部署 Django"></a>部署 Django</h6><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line">#在项目中创建djangospider.ini</span><br><span class="line">[uwsgi]</span><br><span class="line"># 使用Nginx做反向代理时使用socket</span><br><span class="line">#socket=0.0.0.0:8000   </span><br><span class="line"># 不通过Nginx反向代理，直接做web服务器时使用http</span><br><span class="line">http = 0.0.0.0:8000</span><br><span class="line">#项目目录</span><br><span class="line">chdir = /usr/www/DjangoSpider/</span><br><span class="line">wsgi-file = DjangoSpider/wsgi.py</span><br><span class="line">processes = 4</span><br><span class="line">threads = 2</span><br><span class="line"></span><br><span class="line">#django项目setting中</span><br><span class="line">ALLOWED_HOSTS = [] 改为</span><br><span class="line">ALLOWED_HOSTS = [&apos;*&apos;]</span><br><span class="line"></span><br><span class="line">启动：uwsgi --ini  djangospider.ini</span><br></pre></td></tr></table></figure>



<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"></span><br><span class="line">在www中创建uwsgi文件夹，用来存放uwsgi相关文件</span><br><span class="line">#### 启动： </span><br><span class="line">uwsgi --ini xxx.ini</span><br><span class="line">#### 重启：</span><br><span class="line">uwsgi --reload xxx.pid</span><br><span class="line">#### 停止：</span><br><span class="line">uwsgi --stop xxx.pid</span><br></pre></td></tr></table></figure>

<h1 id="配置Nginx"><a href="#配置Nginx" class="headerlink" title="配置Nginx"></a>配置Nginx</h1><p><strong>nginx服务器安装：</strong></p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br></pre></td><td class="code"><pre><span class="line">下载对应当前系统版本的nginx包(package)</span><br><span class="line"># wget  http://nginx.org/packages/centos/7/noarch/RPMS/nginx-release-centos-7-0.el7.ngx.noarch.rpm</span><br><span class="line"></span><br><span class="line">建立nginx的yum仓库</span><br><span class="line"># rpm -ivh nginx-release-centos-7-0.el7.ngx.noarch.rpm</span><br><span class="line"></span><br><span class="line">下载并安装nginx</span><br><span class="line"># yum install -y nginx</span><br><span class="line"></span><br><span class="line">启动nginx服务</span><br><span class="line">systemctl start/restart nginx</span><br><span class="line">验证：直接请求IP，可见nginx</span><br><span class="line"></span><br><span class="line">配置</span><br><span class="line">默认的配置文件在 /etc/nginx 路径下，使用该配置已经可以正确地运行nginx；如需要自定义，修改其下的 nginx.conf 等文件即可。</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">查看是否启动：（如果有master和worker两个进程证明启动成功）</span><br><span class="line">ps -ef | grep nginx</span><br><span class="line"></span><br><span class="line">停止(建议用quit，不建议用stop)</span><br><span class="line">nginx -s quit</span><br><span class="line"></span><br><span class="line">重新加载配置文件</span><br><span class="line">nginx -s reload</span><br><span class="line"></span><br><span class="line">默认配置文件位置</span><br><span class="line">/etc/nginx/conf.d/default.conf</span><br><span class="line">备份默认配置文件</span><br><span class="line">cp  /etc/nginx/conf.d/default.conf /etc/nginx/conf.d/default.conf.bak</span><br><span class="line"></span><br><span class="line">welcome所在位置（默认值：/usr/share/nginx/html/）</span><br></pre></td></tr></table></figure>



<p><strong>修改nginx配置文件：</strong></p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></td><td class="code"><pre><span class="line"># 负载均衡</span><br><span class="line">upstream upstream1 &#123;</span><br><span class="line">    server linux——ip:8000;  # 处理相同业务的多个服务器 (负载均衡)</span><br><span class="line">&#125;</span><br><span class="line">server &#123;</span><br><span class="line">    listen       80;</span><br><span class="line">    server_name  localhost;   # 对外部用户提供的统一域名</span><br><span class="line"></span><br><span class="line">    # 将动态请求转发给uwsgi服务器</span><br><span class="line">    location / &#123;</span><br><span class="line">        # 包含uwsgi请求的参数</span><br><span class="line">        include uwsgi_params;</span><br><span class="line">        # 转交请求给uwsgi服务器 (uwsgi服务器的ip和端口号)</span><br><span class="line">        #uwsgi_pass 127.0.0.1:8000;  # 单个uwsgi服务器(不需要负载均衡)</span><br><span class="line">        uwsgi_pass upstream1;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    # 如果是静态资源请求就直接响应资源。</span><br><span class="line">    location /static &#123;</span><br><span class="line">        # 指定静态文件存放的目录 (需要修改/usr/...目录的操作权限。 $ chmod 777 /usr)</span><br><span class="line">        alias /usr/www/项目名/static/;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p><strong>验证：</strong></p>
<p>nginx -s reload</p>
<p>请求80端口，可能出现permission 问题（办法：先关掉selinux，setenforce 0 ）</p>
<p><strong>收集Django中的静态资源：</strong></p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">项目名/settings.py（项目配置，STATIC_ROOT设置收集静态资源的路径）：</span><br><span class="line">STATIC_URL = &apos;/static/&apos;</span><br><span class="line">STATICFILES_DIRS = [os.path.join(BASE_DIR, &apos;static&apos;)]</span><br><span class="line"># 指定收集静态文件的路径 (需要修改/var/...目录的操作权限)</span><br><span class="line">STATIC_ROOT=&apos;./static&apos;</span><br><span class="line"></span><br><span class="line"># 收集资源</span><br><span class="line">$ python manage.py collectstatic</span><br></pre></td></tr></table></figure>


        </div>
    

</div>
            
                
<div class="post">

    <div class="post-header index">
        <h1 class="title">
            <a href="/blog/2019/06/04/Docker常用命令/">
                Docker常用命令
            </a>
        </h1>
        <div class="post-info">
            
                <span class="date">2019-06-04</span>
            
            
            
        </div>
    </div>

    
        <div class="content">
            <p>显示版本号<br>docker –versions</p>
<p>显示镜像<br>docker images</p>
<p>保存镜像<br>docker save -o /home/dyufei/tensorflow.tar tensorflow/tensorflow</p>
<p>或者 docker save tensorflow/tensorflow &gt; /home/dyufei/tensorflow.tar</p>
<p>加载镜像<br>docker load -i tensorflow.tar</p>
<p>登录系统 镜像编号<br>docker run -ti 6866<br>docker run -it centos /bin/bash</p>
<p>登录系统 容器编号<br>docker run -d –privileged=true mycentos /usr/sbin/init<br>docker exec –it 容器编号 /bin/bash</p>
<p>进入虚拟机<br>docker-machine ssh</p>
<p>挂载共享文件夹<br>docker run -v /www:/mnt/www</p>
<p>查看所有容器<br>docker ps -a</p>
<p>删除容器<br>docker rm</p>
<p>后台启动服务和端口映射</p>
<p>docker run -it -d -p 8000:8000 mycentos cmd</p>
<p>查看宿主ip</p>
<p>docker-machine ip default<br>192.168.99.100</p>
<p>查看容器编号</p>
<p>cat /proc/self/cgroup | head -1</p>
<p>提交更改<br>docker commit 容器id 镜像名称</p>
<p>删除镜像<br>docker rmi -f 镜像id</p>
<p>检查系统<br>cat /etc/redhat-release</p>
<p>退出镜像<br>exit<br>docker run -it ubuntu:rename /bin/echo “Hello World”</p>
<p>删除镜像缓存<br>docker ps -a | grep “Exited” | awk ‘{print $1 }’|xargs docker stop<br>docker ps -a | grep “Exited” | awk ‘{print $1 }’|xargs docker rm</p>
<p>保存导出 docker 镜像到本地<br>docker save -o 路径+文件名.tar 镜像名<br>docker save -o d:/redis.tar redis</p>
<p>读取导入 docker 镜像到docker<br>docker load -i ‘路径+安装包.tar’<br>docker load -i ‘d:/redis.tar’</p>
<p>查看所有容器<br>docker ps -a<br>查看所有容器（运行状态）<br>docker ps</p>
<p>有时候做练习的时候会生成大量的容器，一个一个停用然后删除实在太没有效率了。</p>
<p>1、停用全部运行中的容器:</p>
<p>docker stop $(docker ps -q)</p>
<p>2、删除全部容器：</p>
<p>docker rm $(docker ps -aq)</p>
<p>3、一条命令实现停用并删除容器：</p>
<p>docker stop $(docker ps -q) &amp; docker rm $(docker ps -aq)</p>

        </div>
    

</div>
            
                
<div class="post">

    <div class="post-header index">
        <h1 class="title">
            <a href="/blog/2019/05/14/微服务-Rpc框架/">
                微服务+Rpc框架
            </a>
        </h1>
        <div class="post-info">
            
                <span class="date">2019-05-14</span>
            
            
            
        </div>
    </div>

    
        <div class="content">
            <h1 id="Thirft"><a href="#Thirft" class="headerlink" title="Thirft"></a>Thirft</h1><p>Thrift实际上是实现了C/S模式，通过代码生成工具将接口定义文件生成服务器端和客户端代码从而实现服务端和客户端跨语言的支持用户在Thirft描述文件中声明自己的服务</p>
<p>Thrift最初由facebook开发，07年四月开放源码，08年5月进入apache孵化器。</p>
<p>Apache Thrift 是一款跨语言的服务框架，传输数据采用二进制格式，相对 XML 和 JSON 体积更小，对于高并发、大数据量和多语言的环境更有优势。</p>
<h2 id="数据类型"><a href="#数据类型" class="headerlink" title="数据类型"></a>数据类型</h2><p>Thrift 支持 8 种数据类型：</p>
<p>bool: true or false</p>
<p>byte: signed byte</p>
<p>i16/i32/i64: 16/32/64位 signed integer</p>
<p>double: 64位</p>
<p>binary: byte array</p>
<p>string</p>
<p>3 种容器：</p>
<p>list: 排序数组，可以重复</p>
<p>set: 集合，每个元素唯一</p>
<p>map: t1 唯一</p>
<h1 id="什么是Thrift"><a href="#什么是Thrift" class="headerlink" title="什么是Thrift"></a>什么是Thrift</h1><p>简单来说就是你可以按照Thrift定义语法编写.thrift,然后用Thrift命令行生成各种语言的代码，比如OC、Java、C++、JS，python,调用这些代码就可以完成客户端与服务器的通信了，不需要自己去写网络请求、数据解析等接口</p>
<h1 id="为什么使用Thrift"><a href="#为什么使用Thrift" class="headerlink" title="为什么使用Thrift"></a>为什么使用Thrift</h1><p>在实际项目中主要考虑到这两个优点：</p>
<p>RPC。通过简单定义Thrift描述语言文件，使用Thrift -gen命令可以生成多种语言的代码，这些代码包含了网络通信,数据编解码的功能。这就免去了前后台编写这部分繁琐的代码，同时也统一了前后台的实现逻辑。</p>
<h6 id="Thrift的二进制数据的编码比json更加紧凑、减少了无用的数据的传输"><a href="#Thrift的二进制数据的编码比json更加紧凑、减少了无用的数据的传输" class="headerlink" title="Thrift的二进制数据的编码比json更加紧凑、减少了无用的数据的传输"></a>Thrift的二进制数据的编码比json更加紧凑、减少了无用的数据的传输</h6><h1 id="Thrift的数据编解码"><a href="#Thrift的数据编解码" class="headerlink" title="Thrift的数据编解码"></a>Thrift的数据编解码</h1><h6 id="我们知道json中一个对象类似于这样的：-“key”-”content”-但实际上这个对象只有“content”才是我们真正想要的数据，而“key”这个字符串并不是我们实际需要的，只是为了做一个标记，方便我们查找“content”。而Thrift则可以省去“key”这个多余的字符串。"><a href="#我们知道json中一个对象类似于这样的：-“key”-”content”-但实际上这个对象只有“content”才是我们真正想要的数据，而“key”这个字符串并不是我们实际需要的，只是为了做一个标记，方便我们查找“content”。而Thrift则可以省去“key”这个多余的字符串。" class="headerlink" title="我们知道json中一个对象类似于这样的：{“key”:”content”},但实际上这个对象只有“content”才是我们真正想要的数据，而“key”这个字符串并不是我们实际需要的，只是为了做一个标记，方便我们查找“content”。而Thrift则可以省去“key”这个多余的字符串。"></a>我们知道json中一个对象类似于这样的：{“key”:”content”},但实际上这个对象只有“content”才是我们真正想要的数据，而“key”这个字符串并不是我们实际需要的，只是为了做一个标记，方便我们查找“content”。而Thrift则可以省去“key”这个多余的字符串。</h6><p>我们定义thrift的结构里的属性名称实际上在thrift数据二进制编解码是被忽略的（thrift的json编解码未验证），这个名称的作用只是作为生成的OC代码类的属性名称。这也解释了为什么Thrift的二进制编码会比平时使用的json更省流量。同时也说明了只要我们在.thrift文件中定义struct的时候保证struct的属性的顺序不变，即使通信双方使用了各自使用不同的属性名称也不会有问题。</p>
<h1 id="thriftpy2安装"><a href="#thriftpy2安装" class="headerlink" title="thriftpy2安装"></a>thriftpy2安装</h1><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">pip3 install thriftpy2</span><br></pre></td></tr></table></figure>

<h1 id="thriftpy2使用"><a href="#thriftpy2使用" class="headerlink" title="thriftpy2使用"></a>thriftpy2使用</h1><p>首先定义thrift通讯文件，无论是server服务端和client客户端都需要依赖这个文件进行通讯 文件名可以随便起 pingpong.thrift </p>
<figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line">service PingPong &#123; <span class="comment">#固定的写法 文件里面不可以加注释 注释方便理解</span></span><br><span class="line">    string ping(), </span><br><span class="line">    <span class="comment">#自定义ping（）server和client通讯都需要通过该参数  string代表改参数的数据类型</span></span><br><span class="line">    <span class="comment">#定义多个参数 使用</span></span><br><span class="line">    test(</span><br><span class="line">    	<span class="number">1</span>:数据类型 参数名，</span><br><span class="line">    	<span class="number">2</span>：数据类型 参数名，</span><br><span class="line">    ),</span><br><span class="line">    string check_login(</span><br><span class="line">        <span class="number">1</span>: string username,</span><br><span class="line">        <span class="number">2</span>: string password</span><br><span class="line">    ),</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p> 可以看到我们定义了两个方法，一个有参一个无参，第一个方法用来检测接口是否通信成功，也就是传统的ping命令，第二个方法顾名思义，用户登录</p>
<p>然后建立一个thrift_server.py 建立服务端的代码</p>
<figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">#导包</span></span><br><span class="line"><span class="keyword">import</span> thriftpy2</span><br><span class="line"><span class="comment">#定义变量 = thriftpy2.load() 代表加载我们上面定义的thrift配置文件 module_name代表起一个名字 建议一样</span></span><br><span class="line">pingpong_thrift = thriftpy2.load(<span class="string">"pingpong.thrift"</span>, module_name=<span class="string">"pingpong_thrift"</span>)</span><br><span class="line"><span class="comment">#导入模块rpc 搭建 服务端</span></span><br><span class="line"><span class="keyword">from</span> thriftpy2.rpc <span class="keyword">import</span> make_server</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Dispatcher</span><span class="params">(object)</span>:</span></span><br><span class="line">    <span class="comment">#函数名后面的server调用 里面接受client访问传入的值</span></span><br><span class="line">    <span class="function"><span class="keyword">def</span> <span class="title">ping</span><span class="params">(self)</span>:</span></span><br><span class="line">        <span class="keyword">return</span> <span class="string">"pong"</span></span><br><span class="line">	<span class="comment">#括号里面是cilent发送过来要接受的参数</span></span><br><span class="line">    <span class="function"><span class="keyword">def</span> <span class="title">check_login</span><span class="params">(self,username,password)</span>:</span></span><br><span class="line">        print(username,password)</span><br><span class="line">        <span class="keyword">return</span> <span class="string">'123'</span></span><br><span class="line"><span class="comment">#固定启动服务  上面定义的变量.调用配置文件的函数 ，定义的类（）</span></span><br><span class="line">server = make_server(pingpong_thrift.PingPong, Dispatcher(), <span class="string">'127.0.0.1'</span>, <span class="number">6000</span>)</span><br><span class="line">server.serve()</span><br></pre></td></tr></table></figure>

<p>服务端首先读取通信文件，然后建立起一个服务，监听6000端口，等待客户端请求，实际上服务端的方法也是主要业务逻辑编写的地方。</p>
<p> 随后建立一个thrift_client.py文件，编写客户端代码</p>
<p>​    </p>
<figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> thriftpy2</span><br><span class="line"><span class="comment">#跟上面一样</span></span><br><span class="line">pingpong_thrift = thriftpy2.load(<span class="string">"pingpong.thrift"</span>, module_name=<span class="string">"pingpong_thrift"</span>)</span><br><span class="line"><span class="comment">#导入服务端client</span></span><br><span class="line"><span class="keyword">from</span> thriftpy2.rpc <span class="keyword">import</span> make_client</span><br><span class="line"><span class="comment">#创建服务端访问的接口 </span></span><br><span class="line">client = make_client(pingpong_thrift.PingPong, <span class="string">'127.0.0.1'</span>, <span class="number">6000</span>)</span><br><span class="line"><span class="comment">#服务端要访问的接口</span></span><br><span class="line">print(client.ping())</span><br><span class="line"><span class="comment">#带参数的在括号里面传入相应的参数</span></span><br><span class="line">print(client.check_login(<span class="string">'admin'</span>,<span class="string">'123456'</span>))</span><br></pre></td></tr></table></figure>

<p>下面项目代码实例 框架为tornado</p>
<figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">#测试rpc接口</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">TestRpcHandler</span><span class="params">(BaseHandler)</span>:</span></span><br><span class="line">    <span class="keyword">async</span> <span class="function"><span class="keyword">def</span> <span class="title">get</span><span class="params">(self)</span>:</span></span><br><span class="line">        username = self.get_argument(<span class="string">'username'</span>,<span class="string">'没有收到'</span>)</span><br><span class="line">        print(username)</span><br><span class="line"></span><br><span class="line">        <span class="comment">#登录逻辑不写了，而是直接请求rpc的用户认证服务，所有逻辑全在rpc的server端写</span></span><br><span class="line">        <span class="comment">#获取到 定义的配置文件路径</span></span><br><span class="line">        thrift_path = os.path.dirname(os.path.dirname(__file__))+<span class="string">"/pingpong.thrift"</span></span><br><span class="line">        <span class="keyword">import</span> thriftpy2</span><br><span class="line">        <span class="comment">#读取配置文件</span></span><br><span class="line">        pingpong_thrift = thriftpy2.load(thrift_path, module_name=<span class="string">"pingpong_thrift"</span>)</span><br><span class="line">        <span class="comment">#导入client客户端包 </span></span><br><span class="line">        <span class="keyword">from</span> thriftpy2.rpc <span class="keyword">import</span> make_client</span><br><span class="line">        <span class="comment">#定义要访问的的接口 pingpong_thrift.PingPpong为配置文件的service 的 		PingPong 不导入则报错</span></span><br><span class="line">        client = make_client(pingpong_thrift.PingPong, <span class="string">'127.0.0.1'</span>, <span class="number">6000</span>)</span><br><span class="line"> </span><br><span class="line">		<span class="comment">#访问 server定义的 check_login接口 server接口写入登陆逻辑</span></span><br><span class="line">        print(<span class="string">"thrift返回值是:"</span>+client.check_login(username,<span class="string">'123456'</span>))</span><br><span class="line"></span><br><span class="line">        self.write(<span class="string">'测试rpc'</span>)</span><br></pre></td></tr></table></figure>


        </div>
    

</div>
            
                
<div class="post">

    <div class="post-header index">
        <h1 class="title">
            <a href="/blog/2019/05/13/简单了解rpc/">
                简单了解rpc
            </a>
        </h1>
        <div class="post-info">
            
                <span class="date">2019-05-13</span>
            
            
            
        </div>
    </div>

    
        <div class="content">
            <h1 id="简单了解-RPC"><a href="#简单了解-RPC" class="headerlink" title="简单了解 RPC"></a>简单了解 RPC</h1><h2 id="RPC基本使用"><a href="#RPC基本使用" class="headerlink" title="RPC基本使用"></a>RPC基本使用</h2><p>服务端</p>
<figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># pip install thriftpy2</span></span><br><span class="line"><span class="keyword">import</span> thriftpy2</span><br><span class="line"></span><br><span class="line"><span class="comment">#定义服务</span></span><br><span class="line">tesst_hirift = thriftpy2.load(<span class="string">"tesst_thrift"</span>,module_name=<span class="string">"tesst_hirift"</span>)</span><br><span class="line"></span><br><span class="line"><span class="comment">#导入rpc协议</span></span><br><span class="line"><span class="keyword">from</span> thriiftpy2.rpc <span class="keyword">import</span> make_server</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Dispatcher</span><span class="params">(object)</span>:</span></span><br><span class="line">    <span class="function"><span class="keyword">def</span> <span class="title">ping</span><span class="params">(self)</span>:</span></span><br><span class="line">        <span class="keyword">return</span> <span class="string">'123'</span></span><br><span class="line">    </span><br><span class="line"><span class="keyword">if</span> __name__ == <span class="string">"__main__"</span>:</span><br><span class="line">    server = make_server(tesst_thrift.Test,Dispatcher(),<span class="string">'127.0.0.1'</span>,<span class="number">6000</span>)</span><br><span class="line">    server.server()</span><br></pre></td></tr></table></figure>

<p>客户端：</p>
<p>建一个  test.thrift  文件</p>
<figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">service PingPong &#123;</span><br><span class="line">    string ping(),</span><br><span class="line">    string check_login(</span><br><span class="line">        <span class="number">1</span>: string username,</span><br><span class="line">        <span class="number">2</span>: string password</span><br><span class="line">    ),</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h1 id="概念"><a href="#概念" class="headerlink" title="概念"></a>概念</h1><h2 id="开源-RPC-框架有哪些呢？"><a href="#开源-RPC-框架有哪些呢？" class="headerlink" title="开源 RPC 框架有哪些呢？"></a>开源 RPC 框架有哪些呢？</h2><p>一类是跟某种特定语言平台绑定的，另一类是与语言无关即跨语言平台的。</p>
<h3 id="语言绑定的开源-RPC-框架。"><a href="#语言绑定的开源-RPC-框架。" class="headerlink" title="语言绑定的开源 RPC 框架。"></a>语言绑定的开源 RPC 框架。</h3><ul>
<li>Dubbo：国内最早开源的 RPC 框架，由阿里巴巴公司开发并于 2011 年末对外开源，仅支持 Java 语言。</li>
<li>Motan：微博内部使用的 RPC 框架，于 2016 年对外开源，仅支持 Java 语言。</li>
<li>Tars：腾讯内部使用的 RPC 框架，于 2017 年对外开源，仅支持 C++ 语言。</li>
<li>Spring Cloud：国外 Pivotal 公司 2014 年对外开源的 RPC 框架，仅支持 Java 语言</li>
</ul>
<h3 id="跨语言开源-RPC-框架"><a href="#跨语言开源-RPC-框架" class="headerlink" title="跨语言开源 RPC 框架"></a>跨语言开源 RPC 框架</h3><ul>
<li>gRPC：Google 于 2015 年对外开源的跨语言 RPC 框架，支持多种语言。</li>
<li>Thrift：最初是由 Facebook 开发的内部系统跨语言的 RPC 框架，2007 年贡献给了 Apache 基金，成为 Apache 开源项目之一，支持多种语言。</li>
</ul>
<h4 id="gRPC"><a href="#gRPC" class="headerlink" title="gRPC"></a><strong>gRPC</strong></h4><p>先来看下 gRPC，它的原理是通过 IDL（Interface Definition Language）文件定义服务接口的参数和返回值类型，然后通过代码生成程序生成服务端和客户端的具体实现代码，这样在 gRPC 里，客户端应用可以像调用本地对象一样调用另一台服务器上对应的方法。</p>
<p><img src="https://ask.qcloudimg.com/http-save/yehe-1346475/9cou62nrv6.png?imageView2/2/w/1620" alt="img"></p>
<h5 id="主要特性"><a href="#主要特性" class="headerlink" title="主要特性:"></a>主要特性:</h5><ol>
<li>通信协议采用了 HTTP/2，因为 HTTP/2 提供了连接复用、双向流、服务器推送、请求优先级、首部压缩等机制</li>
<li>IDL 使用了ProtoBuf，ProtoBuf 是由 Google 开发的一种数据序列化协议，它的压缩和传输效率极高，语法也简单</li>
<li>多语言支持，能够基于多种语言自动生成对应语言的客户端和服务端的代码。</li>
</ol>
<h4 id="Thrift"><a href="#Thrift" class="headerlink" title="Thrift"></a><strong>Thrift</strong></h4><p>再来看下 Thrift，Thrift 是一种轻量级的跨语言 RPC 通信方案，支持多达 25 种编程语言。为了支持多种语言，跟 gRPC 一样，Thrift 也有一套自己的接口定义语言 IDL，可以通过代码生成器，生成各种编程语言的 Client 端和 Server 端的 SDK 代码，这样就保证了不同语言之间可以相互通信。它的架构图可以用下图来描述。<img src="https://ask.qcloudimg.com/http-save/yehe-1346475/rkd647j918.png?imageView2/2/w/1620" alt="img"></p>
<h5 id="Thrift-RPC特性"><a href="#Thrift-RPC特性" class="headerlink" title="Thrift RPC特性:"></a>Thrift RPC特性:</h5><ol>
<li>支持多种序列化格式：如 Binary、Compact、JSON、Multiplexed 等。</li>
<li>支持多种通信方式：如 Socket、Framed、File、Memory、zlib 等。</li>
<li>服务端支持多种处理方式：如 Simple 、Thread Pool、Non-Blocking 等。</li>
</ol>

        </div>
    

</div>
            
                
<div class="post">

    <div class="post-header index">
        <h1 class="title">
            <a href="/blog/2019/05/07/线程与进程的区别/">
                线程与进程的区别
            </a>
        </h1>
        <div class="post-info">
            
                <span class="date">2019-05-07</span>
            
            
            
        </div>
    </div>

    
        <div class="content">
            <h2 id="1、线程的基本概念"><a href="#1、线程的基本概念" class="headerlink" title="1、线程的基本概念"></a>1、线程的基本概念</h2><p><strong>概念</strong>：线程是进程中执行运算的最小单位，是进程中的一个实体，是被系统独立调度和分派的基本单位，线程自己不拥有系统资源，只拥有一点在运行中必不可少的资源，但它可与同属一个进程的其它线程共享进程所拥有的全部资源。一个线程可以创建和撤消另一个线程，同一进程中的多个线程之间可以并发执行。</p>
<p><strong>好处</strong> ：<br>（1）易于调度。</p>
<p>（2）提高并发性。通过线程可方便有效地实现并发性。进程可创建多个线程来执行同一程序的不同部分。</p>
<p>（3）开销少。创建线程比创建进程要快，所需开销很少。。</p>
<p>（4）利于充分发挥多处理器的功能。通过创建多线程进程，每个线程在一个处理器上运行，从而实现应用程序的并发性，使每个处理器都得到充分运行。</p>
<h2 id="2、进程的基本概念"><a href="#2、进程的基本概念" class="headerlink" title="2、进程的基本概念"></a>2、进程的基本概念</h2><p>进程（Process）是计算机中的程序关于某数据集合上的一次运行活动，是系统进行资源分配和调度的基本单位，是<a href="https://baike.baidu.com/item/%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F" target="_blank" rel="noopener">操作系统</a>结构的基础。在早期面向进程设计的计算机结构中，进程是程序的基本执行实体；在当代面向线程设计的计算机结构中，进程是线程的容器。程序是指令、数据及其组织形式的描述，进程是程序的实体。 </p>
<h2 id="3、进程的基本状态及状态之间的关系"><a href="#3、进程的基本状态及状态之间的关系" class="headerlink" title="3、进程的基本状态及状态之间的关系"></a>3、进程的基本状态及状态之间的关系</h2><p><strong>状态</strong>：运行、阻塞、挂起阻塞、就绪、挂起就绪</p>
<p><strong>状态之间的转换</strong>：</p>
<p>准备就绪的进程，被CPU调度执行，变成运行态；</p>
<p>运行中的进程，进行I/O请求或者不能得到所请求的资源，变成阻塞态；</p>
<p>运行中的进程，进程执行完毕（或时间片已到），变成就绪态；</p>
<p>将阻塞态的进程挂起，变成挂起阻塞态，当导致进程阻塞的I/O操作在用户重启进程前完成（称之为唤醒），挂起阻塞态变成挂起就绪态，当用户在I/O操作结束之前重启进程，挂起阻塞态变成阻塞态；</p>
<p>将就绪（或运行）中的进程挂起，变成挂起就绪态，当该进程恢复之后，挂起就绪态变成就绪态；</p>
<h2 id="4、线程和进程的关系以及区别？"><a href="#4、线程和进程的关系以及区别？" class="headerlink" title="4、线程和进程的关系以及区别？"></a>4、线程和进程的关系以及区别？</h2><p><strong>进程和线程的关系：</strong></p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">（1）一个线程只能属于一个进程，而一个进程可以有多个线程，但至少有一个线程。</span><br><span class="line"></span><br><span class="line">（2）资源分配给进程，同一进程的所有线程共享该进程的所有资源。</span><br><span class="line"></span><br><span class="line">（3）处理机分给线程，即真正在处理机上运行的是线程。</span><br><span class="line"></span><br><span class="line">（4）线程在执行过程中，需要协作同步。不同进程的线程间要利用消息通信的办法实现同步。线程是指进程内的一个执行单元,也是进程内的可调度实体.</span><br><span class="line">1234567</span><br></pre></td></tr></table></figure>

<p><strong>进程与线程的区别：</strong></p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">（1）调度：线程作为调度和分配的基本单位，进程作为拥有资源的基本单位</span><br><span class="line"></span><br><span class="line">（2）并发性：不仅进程之间可以并发执行，同一个进程的多个线程之间也可并发执行</span><br><span class="line"></span><br><span class="line">（3）拥有资源：进程是拥有资源的一个独立单位，线程不拥有系统资源，但可以访问隶属于进程的资源.</span><br><span class="line"></span><br><span class="line">（4）系统开销：在创建或撤消进程时，由于系统都要为之分配和回收资源，导致系统的开销明显大于创建或撤消线程时的开销。</span><br><span class="line">1234567</span><br></pre></td></tr></table></figure>

<h2 id="5、进程间通信的方式？"><a href="#5、进程间通信的方式？" class="headerlink" title="5、进程间通信的方式？"></a>5、进程间通信的方式？</h2><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line">（1）管道（pipe）及有名管道（named pipe）：管道可用于具有亲缘关系的父子进程间的通信，有名管道除了具有管道所具有的功能外，它还允许无亲缘关系进程间的通信。</span><br><span class="line"></span><br><span class="line">（2）信号（signal）：信号是在软件层次上对中断机制的一种模拟，它是比较复杂的通信方式，用于通知进程有某事件发生，一个进程收到一个信号与处理器收到一个中断请求效果上可以说是一致的。</span><br><span class="line"></span><br><span class="line">（3）消息队列（message queue）：消息队列是消息的链接表，它克服了上两种通信方式中信号量有限的缺点，具有写权限得进程可以按照一定得规则向消息队列中添加新信息；对消息队列有读权限得进程则可以从消息队列中读取信息。</span><br><span class="line"></span><br><span class="line">（4）共享内存（shared memory）：可以说这是最有用的进程间通信方式。它使得多个进程可以访问同一块内存空间，不同进程可以及时看到对方进程中对共享内存中数据得更新。这种方式需要依靠某种同步操作，如互斥锁和信号量等。</span><br><span class="line"></span><br><span class="line">（5）信号量（semaphore）：主要作为进程之间及同一种进程的不同线程之间得同步和互斥手段。</span><br><span class="line"></span><br><span class="line">（6）套接字（socket）：这是一种更为一般得进程间通信机制，它可用于网络中不同机器之间的进程间通信，应用非常广泛。</span><br><span class="line">1234567891011</span><br></pre></td></tr></table></figure>

<h2 id="6、同步和互斥的区别："><a href="#6、同步和互斥的区别：" class="headerlink" title="6、同步和互斥的区别："></a>6、同步和互斥的区别：</h2><p>当有多个线程的时候，经常需要去同步这些线程以访问同一个数据或资源。例如，假设有一个程序，其中一个线程用于把文件读到内存，而另一个线程用于统计文件中的字符数。当然，在把整个文件调入内存之前，统计它的计数是没有意义的。但是，由于每个操作都有自己的线程，操作系统会把两个线程当作是互不相干的任务分别执行，这样就可能在没有把整个文件装入内存时统计字数。为解决此问题，你必须使两个线程同步工作。</p>
<p>所谓同步，是指散步在不同进程之间的若干程序片断，它们的运行必须严格按照规定的某种先后次序来运行，这种先后次序依赖于要完成的特定的任务。如果用对资源的访问来定义的话，同步是指在互斥的基础上（大多数情况），通过其它机制实现访问者对资源的有序访问。在大多数情况下，同步已经实现了互斥，特别是所有写入资源的情况必定是互斥的。少数情况是指可以允许多个访问者同时访问资源。</p>
<p>所谓互斥，是指散布在不同进程之间的若干程序片断，当某个进程运行其中一个程序片段时，其它进程就不能运行它们之中的任一程序片段，只能等到该进程运行完这个程序片段后才可以运行。如果用对资源的访问来定义的话，互斥某一资源同时只允许一个访问者对其进行访问，具有唯一性和排它性。但互斥无法限制访问者对资源的访问顺序，即访问是无序的。</p>
<h2 id="1-线程是什么？进程是什么？二者有什么区别和联系？"><a href="#1-线程是什么？进程是什么？二者有什么区别和联系？" class="headerlink" title="1.线程是什么？进程是什么？二者有什么区别和联系？"></a><strong>1.线程是什么？进程是什么？二者有什么区别和联系？</strong></h2><p>（1）线程是CPU独立运行和独立调度的基本单位；<br>（2）进程是资源分配的基本单位；是执行着的应用程序<br>两者的联系：进程和线程都是操作系统所运行的程序运行的基本单元。<br><strong>区别：</strong><br>（1）进程具有独立的空间地址，一个进程崩溃后，在保护模式下不会对其它进程产生影响。<br>（2）线程只是一个进程的不同执行路径，线程有自己的堆栈和局部变量，但线程之间没有单独的地址空间，一个线程死掉就等于整个进程死掉。</p>
<p>进程是执行着的应用程序，而线程是进程内部的一个执行序列。一个进程可以有多个线程。线程又叫做轻量级进程。</p>
<h2 id="2、线程和进程各自有什么区别和优劣呢？"><a href="#2、线程和进程各自有什么区别和优劣呢？" class="headerlink" title="2、线程和进程各自有什么区别和优劣呢？"></a><strong>2、线程和进程各自有什么区别和优劣呢？</strong></h2><ul>
<li>进程是资源分配的最小单位，线程是程序执行的最小单位。</li>
<li>进程有自己的独立地址空间，每启动一个进程，系统就会为它分配地址空间，建立数据表来维护代码段、堆栈段和数据段，这种操作非常昂贵。而线程是共享进程中的数据的，使用相同的地址空间，因此CPU切换一个线程的花费远比进程要小很多，同时创建一个线程的开销也比进程要小很多。</li>
<li>线程之间的通信更方便，同一进程下的线程共享全局变量、静态变量等数据，而进程之间的通信需要以通信的方式（IPC)进行。不过如何处理好同步与互斥是编写多线程程序的难点。</li>
<li>但是多进程程序更健壮，多线程程序只要有一个线程死掉，整个进程也死掉了，而一个进程死掉并不会对另外一个进程造成影响，因为进程有自己独立的地址空间。</li>
</ul>
<h2 id><a href="#" class="headerlink" title=" "></a> </h2><h2 id="3、创建线程有几种不同的方式？你喜欢哪一种？为什么？"><a href="#3、创建线程有几种不同的方式？你喜欢哪一种？为什么？" class="headerlink" title="3、创建线程有几种不同的方式？你喜欢哪一种？为什么？"></a><strong>3、创建线程有几种不同的方式？你喜欢哪一种？为什么？</strong></h2><p>有三种方式可以用来创建线程：</p>
<ul>
<li>继承Thread类</li>
<li>实现Runnable接口</li>
<li>应用程序可以使用Executor框架来创建线程池</li>
</ul>
<p>实现Runnable接口这种方式更受欢迎，因为这不需要继承Thread类。在应用设计中已经继承了别的对象的情况下，这需要多继承（而Java不支持多继承），只能实现接口。同时，线程池也是非常高效的，很容易实现和使用。</p>
<h2 id="4、概括的解释下线程的几种可用状态。"><a href="#4、概括的解释下线程的几种可用状态。" class="headerlink" title="4、概括的解释下线程的几种可用状态。"></a><strong>4、概括的解释下线程的几种可用状态。</strong></h2><p>线程在执行过程中，可以处于下面几种状态：</p>
<ul>
<li>就绪(Runnable):线程准备运行，不一定立马就能开始执行。</li>
<li>运行中(Running)：进程正在执行线程的代码。</li>
<li>等待中(Waiting):线程处于阻塞的状态，等待外部的处理结束。</li>
<li>睡眠中(Sleeping)：线程被强制睡眠。</li>
<li>I/O阻塞(Blocked on I/O)：等待I/O操作完成。</li>
<li>同步阻塞(Blocked on Synchronization)：等待获取锁。</li>
<li>死亡(Dead)：线程完成了执行。</li>
</ul>
<h2 id="-1"><a href="#-1" class="headerlink" title=" "></a> </h2><h2 id="5、同步方法和同步代码块的区别是什么？"><a href="#5、同步方法和同步代码块的区别是什么？" class="headerlink" title="5、同步方法和同步代码块的区别是什么？"></a><strong>5、同步方法和同步代码块的区别是什么？</strong></h2><p>在Java语言中，每一个对象有一把锁。线程可以使用synchronized关键字来获取对象上的锁。synchronized关键字可应用在方法级别(粗粒度锁)或者是代码块级别(细粒度锁)。</p>
<p>Java语言的关键字，当它用来修饰一个方法或者一个代码块的时候，能够保证在同一时刻最多只有一个线程执行该段代码。</p>
<p>​     （1）、当两个并发线程访问同一个对象object中的这个synchronized(this)同步代码块时，一个时间内只能有一个线程得到执行。另一个线程必须等待当前线程执行完这个代码块以后才能执行该代码块。</p>
<p>​     （2）、然而，当一个线程访问object的一个synchronized(this)同步代码块时，另一个线程仍然可以访问该object中的非synchronized(this)同步代码块。</p>
<p>​     （3）、尤其关键的是，当一个线程访问object的一个synchronized(this)同步代码块时，其他线程对object中所有其它synchronized(this)同步代码块的访问将被阻塞。</p>
<p>​     （4）、第三个例子同样适用其它同步代码块。也就是说，当一个线程访问object的一个synchronized(this)同步代码块时，它就获得了这个object的对象锁。结果，其它线程对该object对象所有同步代码部分的访问都被暂时阻塞。</p>
<p>​     （5）、以上规则对其它对象锁同样适用。</p>
<h2 id="6、在监视器-Monitor-内部，是如何做线程同步的？程序应该做哪种级别的同步？"><a href="#6、在监视器-Monitor-内部，是如何做线程同步的？程序应该做哪种级别的同步？" class="headerlink" title="6、在监视器(Monitor)内部，是如何做线程同步的？程序应该做哪种级别的同步？"></a><strong>6、在监视器(Monitor)内部，是如何做线程同步的？程序应该做哪种级别的同步？</strong></h2><p>监视器和锁在Java虚拟机中是一块使用的。监视器监视一块同步代码块，确保一次只有一个线程执行同步代码块。每一个监视器都和一个对象引用相关联。线程在获取锁之前不允许执行同步代码。</p>
<h2 id="7、什么是死锁-deadlock-？"><a href="#7、什么是死锁-deadlock-？" class="headerlink" title="7、什么是死锁(deadlock)？"></a><strong>7、什么是死锁(deadlock)？</strong></h2><p>两个进程都在等待对方执行完毕才能继续往下执行的时候就发生了死锁。结果就是两个进程都陷入了无限的等待中。</p>
<h2 id="8、如何确保N个线程可以访问N个资源同时又不导致死锁？"><a href="#8、如何确保N个线程可以访问N个资源同时又不导致死锁？" class="headerlink" title="8、如何确保N个线程可以访问N个资源同时又不导致死锁？"></a><strong>8、如何确保N个线程可以访问N个资源同时又不导致死锁？</strong></h2><p>使用多线程的时候，一种非常简单的避免死锁的方式就是：指定获取锁的顺序，并强制线程按照指定的顺序获取锁。因此，如果所有的线程都是以同样的顺序加锁和释放锁，就不会出现死锁了。</p>
<h2 id="9、如何避免死锁"><a href="#9、如何避免死锁" class="headerlink" title="9、如何避免死锁?"></a><strong>9、如何避免死锁?</strong></h2><p><strong>多线程产生死锁的四个必要条件：</strong></p>
<ol>
<li>互斥条件：一个资源每次只能被一个进程使用。</li>
<li>保持和请求条件：一个进程因请求资源而阻塞时，对已获得资源保持不放。</li>
<li>不可剥夺调教：进程已获得资源，在未使用完成前，不能被剥夺。</li>
<li>循环等待条件：若干进程之间形成一种头尾相接的循环等待资源关系。</li>
</ol>

        </div>
    

</div>
            
                
<div class="post">

    <div class="post-header index">
        <h1 class="title">
            <a href="/blog/2019/05/02/锁的详解/">
                锁的详解
            </a>
        </h1>
        <div class="post-info">
            
                <span class="date">2019-05-02</span>
            
            
            
        </div>
    </div>

    
        <div class="content">
            <h1 id="锁"><a href="#锁" class="headerlink" title="锁"></a>锁</h1><h2 id="全局解释器锁"><a href="#全局解释器锁" class="headerlink" title="全局解释器锁"></a>全局解释器锁</h2><p>​    1、什么是全局解释器锁</p>
<p>　　　　　　在同一个进程中只要有一个线程获取了全局解释器（cpu）的使用权限，那么其他的线程就必须等待该线程的全局解释器（cpu）使　　　　用权消失后才能使用全局解释器（cpu）,即时多个线程直接不会相互影响在同一个进程下也只有一个线程使用cpu，这样的机制称为全局　　　　解释器锁（GIL）。</p>
<p>　　2、全局解释器锁的好处</p>
<p>　　　　　　1、避免了大量的加锁解锁的好处</p>
<p>　　　　　　2、使数据更加安全，解决多线程间的数据完整性和状态同步</p>
<p>　　3、全局解释器的缺点</p>
<p>　　　　　　多核处理器退化成单核处理器，只能并发不能并行。</p>
<p>同一时刻的某个进程下的某个线程只能被一个cpu所处理，所以在GIL锁下的线程只能被并发，不能被并行。 </p>
<h3 id="Ps-GIL锁"><a href="#Ps-GIL锁" class="headerlink" title="Ps:GIL锁"></a>Ps:GIL锁</h3><p>GIL全称Global Interpreter Lock，即全局解释器锁。 作用就是，限制多线程同时执行，保证同一时间内只有一个线程在执行</p>
<h2 id="并发与并行"><a href="#并发与并行" class="headerlink" title="并发与并行"></a>并发与并行</h2><h2 id="互斥锁"><a href="#互斥锁" class="headerlink" title="互斥锁"></a>互斥锁</h2><p><strong>概念:</strong><br>互斥就是互相排斥的意思,在多个进程或线程对同一个资源请求的时候,如果每个进程或线程请求的时候都加锁,别的进程或线程就没法访问这里的资源,就会一直等待.直到占用该资源的那个进程或线程释放了该锁.所以互斥锁又叫排他锁,又叫同步锁.</p>
<p>　　1、什么是同步锁？</p>
<p>　　　　同一时刻的一个进程下的一个线程只能使用一个cpu，要确保这个线程下的程序在一段时间内被cpu执，那么就要用到同步锁。</p>
<p>　　2、为什么用同步锁？</p>
<p>　　　　因为有可能当一个线程在使用cpu时，该线程下的程序可能会遇到io操作，那么cpu就会切到别的线程上去，这样就有可能会影响到该程　　序结果的完整性。</p>
<p>　　3、怎么使用同步锁？</p>
<p>　　　　只需要在对公共数据的操作前后加上上锁和释放锁的操作即可。</p>
<h3 id="Ps-扩展知识"><a href="#Ps-扩展知识" class="headerlink" title="Ps:扩展知识"></a>Ps:扩展知识</h3><p>　　　　1、GIL的作用：多线程情况下必须存在资源的竞争，GIL是为了保证在解释器级别的线程唯一使用共享资源（cpu）。</p>
<p>　　　　2、同步锁的作用：为了保证解释器级别下的自己编写的程序唯一使用共享资源产生了同步锁。</p>
<h2 id="递归锁和死锁"><a href="#递归锁和死锁" class="headerlink" title="递归锁和死锁"></a>递归锁和死锁</h2><p>什么是死锁？</p>
<p>　　　　指两个或两个以上的线程或进程在执行程序的过程中，因争夺资源而相互等待的一个现象</p>
<p>什么是递归锁？</p>
<p>　　　　在Python中为了支持同一个线程中多次请求同一资源，Python提供了可重入锁。这个RLock内部维护着一个Lock和一个counter</p>
<p>　　变量，counter记录了acquire的次数，从而使得资源可以被多次require。直到一个线程所有的acquire都被release，其他的线程才能获</p>
<h2 id="什么是信号量？"><a href="#什么是信号量？" class="headerlink" title="什么是信号量？"></a>什么是信号量？</h2><p>　　　　同进程的一样，semaphore管理一个内置的计数器，每当调用acquire()时内置函数-1，每当调用release()时内置函数+1。</p>
<p>　　　计数器不能为0，当计数器为0时acquire（）将阻塞线程，直到其他线程调用release（）。</p>
<h1 id="MySql的乐观锁和悲观锁"><a href="#MySql的乐观锁和悲观锁" class="headerlink" title="MySql的乐观锁和悲观锁"></a>MySql的乐观锁和悲观锁</h1><h2 id="悲观锁"><a href="#悲观锁" class="headerlink" title="悲观锁"></a><strong>悲观锁</strong></h2><p>悲观锁(Pessimistic Lock),顾名思义就是很悲观.每次去操作数据的时候,都会认为别人会修改.所以为了防止别人修改,就在操作的时候上锁.这样别人来访问的时候就会阻塞在那里直到锁被是释放.传统的关系型数据库里面就用到了很多这种锁机制,比如行锁,表锁,读锁,写锁等,都是在操作之前先上锁.</p>
<p><strong>使用场景:</strong><br>商品goods表中有一个字段status,status为1代表商品未被下单,status为2代表商品已经被下单,那么我们对某个商品下单的时候必须确保该商品status为1.假设商品id为1.</p>
<p><strong>优点和不足</strong><br>悲观锁的策略是先取锁再访问,保证了数据的安全性.但是效率方面,处理加锁机制会让数据库产生额外的开销.<br>还有即使增加了产生死锁的可能.<br>所以一般只有在写的操作冲突多的时候才使用悲观锁,而读的操作不需要加锁.</p>
<h2 id="乐观锁"><a href="#乐观锁" class="headerlink" title="乐观锁"></a>乐观锁</h2><p>乐观锁(Optimistic Lock),顾名思义,就是很乐观,每次去拿数据的时候都认为比人不会修改,所以不会上锁.<br>但是在更新数据的时候,会判断一下在更新数据的这段时间内,数据有没有被修改.如果被修改了,如果被修改了<br>就取消这次操作,如果没有被修改,则使得这次操作生效.一般使用版本号或者时间戳的方式来实现.</p>
<p><strong>优点和不足</strong> 乐观并发控制相信事务之间的数据竞争的概率是比较小的,会先进行操作. 再提交的时候再进行验证这次提交是否可行,因此不会有任何的死锁和锁.但是这样做 还是有问题的,例如如果某两个事务对同一行的数据同时进行了修改,经过修改之后, 同时写进了数据库,这时就会出现问题.所以乐观锁,一般用在读数据比较多的地方. 而对于写数据比较多的地方,我们最好使用悲观锁来解决. </p>
<h2 id="行级锁和死锁"><a href="#行级锁和死锁" class="headerlink" title="行级锁和死锁"></a><strong>行级锁和死锁</strong></h2><p>在MySql中,行级锁并不是直接锁记录,而是锁索引.索引分为主键索引和非主键索引两种.<br>如果一条sql语句操作了主键索引,MySql就会锁住这条主键索引.如果一条语句操作了<br>非主键索引,MySQL会先锁定该非主键索引,再锁定相关的主键索引.在UPDATE,DELETE操作时,<br>MYSQL不仅锁定WHERE条件扫描过的所有索引记录,而且会锁定相邻的键值,即所谓的<br>next-key locking<br>当两个事务同时执行,一个锁住了主键索引,在等待其他相关索引.另一个锁住了非主键索引,在等待主键索引.<br>就发生了死锁.</p>
<p>放生死锁以后,一般InnoDB可以检测到,会将一个事务进行回滚,释放掉占用的锁.另一个事务获取到锁完成事务.</p>

        </div>
    

</div>
            
                
<div class="post">

    <div class="post-header index">
        <h1 class="title">
            <a href="/blog/2019/04/15/三元表达式/">
                三元表达式
            </a>
        </h1>
        <div class="post-info">
            
                <span class="date">2019-04-15</span>
            
            
            
        </div>
    </div>

    
        <div class="content">
            <p>三元条件表达式</p>
<p>condition ? true_part : false_part</p>
<p>语法是  结果1? 条件 : 结果2;. 这里你把条件写在问号(?)的前面后面跟着用冒号(:)分隔的结果1和结果2。满足条件时结果1否则结果2</p>

        </div>
    

</div>
            
                
<div class="post">

    <div class="post-header index">
        <h1 class="title">
            <a href="/blog/2019/04/12/如何快速搭建hexo技术博客/">
                如何快速搭建hexo技术博客
            </a>
        </h1>
        <div class="post-info">
            
                <span class="date">2019-04-12</span>
            
            
            
        </div>
    </div>

    
        <div class="content">
            <h1 id="使用Hexo配合-码云-建立一个轻量、简易、高逼格的博客"><a href="#使用Hexo配合-码云-建立一个轻量、简易、高逼格的博客" class="headerlink" title="使用Hexo配合 码云 建立一个轻量、简易、高逼格的博客"></a>使用Hexo配合 码云 建立一个轻量、简易、高逼格的博客</h1><p>​    建立一个简单的个人博客系统，它是基于go lang的，其实，市面上还有一款类似的静态页生成器，就是Hexo 读音/hækso/ ，它是基于node.js的，和Hugo一样，Hexo 正常来说，不需要部署到我们的服务器上，我们的服务器上保存的，其实是基于在hexo通过markdown编写的文章，然后hexo帮我们生成静态的html页面，然后，将生成的html上传到我们的服务器。简而言之：hexo是个静态页面生成、上传的工具。</p>
<p>​    首先安装Hexo，在此之前，请确保电脑里已经安装好新版的node.js</p>
<p>然后全局安装npm或cnpm：</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">npm install -g hexo-cli</span><br></pre></td></tr></table></figure>

<p>​    如果感觉安装速度比较慢，可以为cnpm指定国内的源</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">npm config set registry https://registry.npm.taobao.org</span><br></pre></td></tr></table></figure>

<p>​    安装完成后，创建博客项目</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">hexo init blog</span><br></pre></td></tr></table></figure>

<p>​    这样，就建立起了一个blog文件夹，进入到blog目录下 cd blog，建立第一篇文章</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">hexo new myfirst</span><br></pre></td></tr></table></figure>

<p>​    然后运行hexo服务</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">hexo server</span><br></pre></td></tr></table></figure>

<p>​    就可以在本地访问你的博客网站了，默认端口号是4000</p>
<p>​    那么如何将博客网站打包呢？直接运行打包命令，这样就能使用 Hexo 引擎将 Markdown 格式的文件解析成可以使用浏览器查看的 HTML 文件，HTML 文件存储在 blog/public 目录下</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">hexo generate</span><br></pre></td></tr></table></figure>

<p>​    下面我们可以配置一下hexo主题，Hexo 提供了默认主题 landscape，主题的位置在 blog -&gt;themes 文件夹下。主题根据自己喜好可以在网上找到:<a href="https://hexo.io/themes/" target="_blank" rel="noopener">https://hexo.io/themes/</a></p>
<p>​    主题都放在blog/themes文件夹下面，这我们下载一个新的主题</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">mkdir themes/next</span><br><span class="line">git clone --branch v5.1.2 https://github.com/iissnan/hexo-theme-next themes/next</span><br></pre></td></tr></table></figure>

<p>​    然后在修改 /blog/config.yml 文件，将其中的 theme 改成 next</p>
<p>再使用</p>
<figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">hexo g  <span class="comment"># 收集并生成静态资源到public</span></span><br></pre></td></tr></table></figure>

<p>接下来 把你的public文件夹内的静态资源 push到 制定的博客仓库去</p>
<p>点击服务</p>
<p>选择 强制HTTPS</p>
<p>点击保存 </p>
<p>然后就会生成 博客的域名连接 </p>
<p>访问连接就可以访问到你的博客啦</p>
<p>当然 这样你的静态资源可能 无法生效</p>
<p>那么接下来针对这个配置修改你的 /blog/config.yml 文件</p>
<p>顺道先把主题标题 和 作者改了</p>
<p>别信辛苦写的博客，展示成别人的作品</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">title: CK   # 标题 </span><br><span class="line">author: ck   # 作者</span><br><span class="line">language: zh	# 支持中文</span><br></pre></td></tr></table></figure>

<p>配置资源路由：</p>
<figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">url: https://chenkai0309.gitee.io   <span class="comment"># 服务生成的微博链接</span></span><br><span class="line">root: /blog/    <span class="comment"># 连接后缀地址</span></span><br></pre></td></tr></table></figure>

<p>配置 码云对接参数</p>
<figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">deploy:</span><br><span class="line">  type:git    <span class="comment"># 请求类型</span></span><br><span class="line">  repo:- gitee.com/chenkai0309/blog.git  <span class="comment"># 微博专用码云仓库地址</span></span><br><span class="line">  branch:master		<span class="comment"># 选择分支</span></span><br></pre></td></tr></table></figure>

<p>然后 重新收集收集并生成静态资源到public</p>
<figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">hexo g  <span class="comment"># 收集并生成静态资源到public</span></span><br></pre></td></tr></table></figure>

<p>最后再一次将public提交push到码云微博仓库去  Ps:注意版本号</p>
<p>点击仓库服务</p>
<p>点击 更新</p>
<p>再次访问 为博客链接  </p>
<p>主题完美显示</p>
<p>就这样博客就搭完了</p>

        </div>
    

</div>
            
                
<div class="post">

    <div class="post-header index">
        <h1 class="title">
            <a href="/blog/2019/04/04/利用Redissearch结合python3做全文检索/">
                利用Redissearch结合python3做全文检索
            </a>
        </h1>
        <div class="post-info">
            
                <span class="date">2019-04-04</span>
            
            
            
        </div>
    </div>

    
        <div class="content">
            <h1 id="使用python3和高性能全文检索引擎Redisearch进行交互"><a href="#使用python3和高性能全文检索引擎Redisearch进行交互" class="headerlink" title="使用python3和高性能全文检索引擎Redisearch进行交互"></a>使用python3和高性能全文检索引擎Redisearch进行交互</h1><p><a href="https://v3u.cn/" target="_blank" rel="noopener">首页</a> - <a href="https://v3u.cn/l_id_1" target="_blank" rel="noopener">Python</a> /2019-08-30</p>
<p>​    上一篇介绍了一款<a href="https://v3u.cn/a_id_105" target="_blank" rel="noopener">高性能全文检索引擎Redisearch</a>，它不仅性能强劲，部署也方便，这里介绍一下如何用python客户端和它进行交互。使用redisearch-python:<a href="https://github.com/RediSearch/redisearch-py" target="_blank" rel="noopener">https://github.com/RediSearch/redisearch-py</a></p>
<p>​    首先，安装</p>
<p>​    </p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">pip3 install redisearch</span><br></pre></td></tr></table></figure>

<p>​    基本操作:</p>
<p>​    </p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line">from redisearch import Client, TextField</span><br><span class="line"># Creating a client with a given index name</span><br><span class="line">client = Client(&apos;myIndex&apos;,host=&apos;localhost&apos;,port=&apos;6666&apos;)</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"># Creating the index definition and schema</span><br><span class="line">client.create_index((TextField(&apos;title&apos;), TextField(&apos;body&apos;)))</span><br><span class="line"></span><br><span class="line"># Indexing a document</span><br><span class="line">client.add_document(&apos;doc2&apos;, title = &apos;你好&apos;, body = &apos;我在北京学习人工智能&apos;,language=&apos;chinese&apos;)</span><br><span class="line"></span><br><span class="line"># Simple search</span><br><span class="line">res = client.search(&quot;人工智能&quot;)</span><br><span class="line"></span><br><span class="line">print(res.docs[0].title)</span><br></pre></td></tr></table></figure>

<p>​    可以看到，基本上和命令行中的操作方式没有太大区别，只是在search时不需要指定语言了，程序可以自主判断。</p>
<p>​    其实它的官方文档很简单，只是介绍了基本用法，但是你如果阅读了它的源码，发现一些常用操作它也进行了封装，比如</p>
<p>​    </p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">#删除索引</span><br><span class="line">client.drop_index()</span><br><span class="line"></span><br><span class="line">#获取当前索引的基本信息</span><br><span class="line">client.info()</span><br><span class="line"></span><br><span class="line">#删除文档</span><br><span class="line">client.delete_document(&apos;doc2&apos;)</span><br></pre></td></tr></table></figure>
        </div>
    

</div>
            
                
<div class="post">

    <div class="post-header index">
        <h1 class="title">
            <a href="/blog/2019/04/03/在django模板中只显示前n条记录/">
                在django模板中只显示前n条记录
            </a>
        </h1>
        <div class="post-info">
            
                <span class="date">2019-04-03</span>
            
            
            
        </div>
    </div>

    
        <div class="content">
            <h1 id="在django-模板中只显示前n条记录"><a href="#在django-模板中只显示前n条记录" class="headerlink" title="在django 模板中只显示前n条记录"></a>在django 模板中只显示前n条记录</h1><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">&#123;% <span class="keyword">for</span> subject <span class="keyword">in</span> categroy.subject_set.all|slice:<span class="string">":5"</span> %&#125;</span><br></pre></td></tr></table></figure>


        </div>
    

</div>
            
        </section>
    </div>
</div>



    <div class="row">
        <div class="col-sm-12">
            <div class="wrap-pagination">
                <a class="" href="/blog/page/3/">
                    <i class="fa fa-chevron-left" aria-hidden="true"></i>
                </a>
                <a class="" href="/blog/page/5/">
                    <i class="fa fa-chevron-right" aria-hidden="true"></i>
                </a>
            </div>
        </div>
    </div>




</div>

<!-- Footer -->
<div class="push"></div>

<footer class="footer-content">
    <div class="container">
        <div class="row">
            <div class="col-xs-12 col-sm-12 col-md-6 col-lg-6 footer-about">
                <h2>About</h2>
                <p>
                    This theme was developed by <a href="https://github.com/klugjo">Jonathan Klughertz</a>. The source code is available on Github. Create Websites. Make Magic.
                </p>
            </div>
            
    <div class="col-xs-6 col-sm-6 col-md-3 col-lg-3 recent-posts">
        <h2>Recent Posts</h2>
        <ul>
            
            <li>
                <a class="footer-post" href="/blog/2019/10/25/tars框架环境基础搭建/">tars框架环境基础搭建</a>
            </li>
            
            <li>
                <a class="footer-post" href="/blog/2019/10/20/认识tars框架/">认识tars框架</a>
            </li>
            
            <li>
                <a class="footer-post" href="/blog/2019/10/05/redis数据迁移备份与恢复/">redis数据迁移备份与恢复</a>
            </li>
            
            <li>
                <a class="footer-post" href="/blog/2019/09/21/负载均衡的5种策略/">负载均衡的5种策略</a>
            </li>
            
        </ul>
    </div>



            
        </div>
        <div class="row">
            <div class="col-xs-12 col-sm-12 col-md-12 col-lg-12">
                <ul class="list-inline footer-social-icons">
                    
                    <li class="list-inline-item">
                        <a href="https://github.com/klugjo/hexo-theme-alpha-dust">
                            <span class="footer-icon-container">
                                <i class="fa fa-github"></i>
                            </span>
                        </a>
                    </li>
                    
                    
                    <li class="list-inline-item">
                        <a href="https://twitter.com/?lang=en">
                            <span class="footer-icon-container">
                                <i class="fa fa-twitter"></i>
                            </span>
                        </a>
                    </li>
                    
                    
                    <li class="list-inline-item">
                        <a href="https://www.facebook.com/">
                            <span class="footer-icon-container">
                                <i class="fa fa-facebook"></i>
                            </span>
                        </a>
                    </li>
                    
                    
                    <li class="list-inline-item">
                        <a href="https://www.instagram.com/">
                            <span class="footer-icon-container">
                                <i class="fa fa-instagram"></i>
                            </span>
                        </a>
                    </li>
                    
                    
                    <li class="list-inline-item">
                        <a href="https://dribbble.com/">
                            <span class="footer-icon-container">
                                <i class="fa fa-dribbble"></i>
                            </span>
                        </a>
                    </li>
                    
                    
                    <li class="list-inline-item">
                        <a href="https://plus.google.com/">
                            <span class="footer-icon-container">
                                <i class="fa fa-google-plus"></i>
                            </span>
                        </a>
                    </li>
                    
                    
                    <li class="list-inline-item">
                        <a href="https://www.behance.net/">
                            <span class="footer-icon-container">
                                <i class="fa fa-behance"></i>
                            </span>
                        </a>
                    </li>
                    
                    
                    <li class="list-inline-item">
                        <a href="https://500px.com/">
                            <span class="footer-icon-container">
                                <i class="fa fa-500px"></i>
                            </span>
                        </a>
                    </li>
                    
                    
                    <li class="list-inline-item">
                        <a href="mailto:test@example.com">
                            <span class="footer-icon-container">
                                <i class="fa fa-envelope-o"></i>
                            </span>
                        </a>
                    </li>
                    
                    
                    <li class="list-inline-item">
                        <a href="\#">
                            <span class="footer-icon-container">
                                <i class="fa fa-rss"></i>
                            </span>
                        </a>
                    </li>
                    
                </ul>
            </div>
        </div>
        <div class="row">
            <div class="col-xs-12 col-sm-12 col-md-12 col-lg-12">
                <div class="footer-copyright">
                    @Untitled. All right reserved | Design & Hexo <a href="http://www.codeblocq.com/">Jonathan Klughertz</a>
                </div>
            </div>
        </div>
    </div>
</footer>

<!-- After footer scripts -->

<!-- jQuery -->
<script src="//code.jquery.com/jquery-2.1.4.min.js"></script>

<!-- Tween Max -->
<script src="//cdnjs.cloudflare.com/ajax/libs/gsap/1.18.5/TweenMax.min.js"></script>

<!-- Gallery -->
<script src="//cdnjs.cloudflare.com/ajax/libs/featherlight/1.3.5/featherlight.min.js" type="text/javascript" charset="utf-8"></script>

<!-- Custom JavaScript -->
<script src="/blog/js/main.js"></script>

<!-- Disqus Comments -->



</body>

</html>